﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Policy;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace GameNode
{
    class NodeGameLogic
   {
       private readonly GameField gameField;
       private readonly Drawer drawer;
       private readonly Random rnd;
       private List<ConsoleNode> nodes;
       private ConsoleNode target;
       private int nodeCount;
       private readonly InputHandler _ih;
       private Direction dir=Direction.Up;
       public int speed = 1;
       public int tailCount = 3;
       public bool isGameOver = false;



        public NodeGameLogic(GameField gameField, Drawer drawer, int nodeCount, InputHandler ih)
        {
            this.gameField = gameField;
            this.drawer = drawer;
            this.nodeCount = nodeCount;  

            _ih = ih;
            _ih.KeyLeft += MoveNodeLeft;
            _ih.KeyRight += MoveNodeRight;
            _ih.KeyUp += MoveNodeUp;
            _ih.KeyDown += MoveNodeDown;


            rnd = new Random();
            nodes = new List<ConsoleNode>();
            target = GenerateRandomTarget((char) 1, ConsoleColor.White);

        }


        public void StartGame()
        {

           
            for (int z = 0; z < 1000; z++)
                {

                    nodes = new List<ConsoleNode>()
                    {
                    new ConsoleNode(((gameField.X+(gameField.X+gameField.Width))/2),((gameField.Y+(gameField.Y+gameField.Height))/2),'A',  ConsoleColor.Red),
                    new ConsoleNode(((gameField.X+(gameField.X+gameField.Width))/2),(((gameField.Y+(gameField.Y+gameField.Height))/2)+1),'A', ConsoleColor.Red),
                    new ConsoleNode(((gameField.X+(gameField.X+gameField.Width))/2),(((gameField.Y+(gameField.Y+gameField.Height))/2)+2),'A', ConsoleColor.Red),

                     };
              
                    EndOfTheGame();
            


                        do
                        {
                            drawer.DrawGameField(gameField, '0');
                            drawer.DrawNodeList(nodes);
                            drawer.DrawNode(target);
                            _ih.QueryKB();

                  
                            TailMoving(nodes);
                            HeadMoving(nodes[0], dir, CheckPosition);


                            for (int i = 0; i < nodes.Count; i++)
                            {
                                if (IsNodeOnTarget(nodes[i]))
                                {

                               
                                    nodes.Add(new ConsoleNode(target.X, target.Y, 'A', ConsoleColor.Red));
                                    tailCount++;
                           
                                     if (tailCount == 5)
                                      {
                                        drawer.DrawMessage(gameField, 10, "Next level");
                                        speed++;
                                        tailCount = 3;
                                        dir = Direction.Up;
                                        StartGame();
                                      }

                                    target = GenerateRandomTarget((char)1, ConsoleColor.White);
                                

                                }
                            }
                         drawer.DrawListAndScore(gameField, 5,speed, tailCount);
                         Thread.Sleep(250 - speed*10);


                         }
                        while (!isGameOver);
                    

                 }
            Console.ReadKey();
        }

        public void TailMoving(List<ConsoleNode> nodesList)
        {
            for (int i = nodesList.Count - 1; i > 0; i--)
             {

                nodesList[i].X= nodesList[i - 1].X;
                nodesList[i].Y = nodesList[i - 1].Y;

             }
        }

        public void HeadMoving(ConsoleNode node, Direction dir, Func<int, int, Position> positionStatus)
        {
            

            if (dir == Direction.Up)
            {
                if (positionStatus(node.X, node.Y - 1) == Position.Free)
                    node.MoveUp();
                else if ((positionStatus(node.X, node.Y - 1) == Position.Border) || (positionStatus(node.X, node.Y - 1) == Position.Node))
                   isGameOver = true;
                   

            }
            if (dir == Direction.Down)
            {
                if (positionStatus(node.X, node.Y + 1) == Position.Free)
                    node.MoveDown();
                else if ((positionStatus(node.X, node.Y + 1) == Position.Border) || (positionStatus(node.X, node.Y + 1) == Position.Node))
                    isGameOver = true;

            }
            if (dir == Direction.Left)
            {
                if (positionStatus(node.X-1, node.Y) == Position.Free)
                    node.MoveLeft();
                else if ((positionStatus(node.X-1, node.Y) == Position.Border) || (positionStatus(node.X-1, node.Y) == Position.Node))
                    isGameOver = true;

            }
            if (dir == Direction.Right)
            {
                if (positionStatus(node.X + 1, node.Y) == Position.Free)
                    node.MoveRight();
                else if ((positionStatus(node.X + 1, node.Y) == Position.Border) || (positionStatus(node.X + 1, node.Y) == Position.Node))
                    isGameOver = true;
            }


        }
       
        private ConsoleNode GenerateRandomTarget(char symbol, ConsoleColor color)
        {

            int randomX = 0;
            int randomY = 0;
            do
            {
                randomX = rnd.Next(gameField.X, gameField.Width + gameField.X);
                randomY = rnd.Next(gameField.Y, gameField.Height + gameField.Y);

            } while (!IsPositionFree(randomX, randomY));

            return new ConsoleNode(randomX, randomY, symbol, color);
        }

    

       private bool IsPositionFree(int x, int y)
       {
            foreach (var nd in nodes)
            {
                if (nd.IsOnPossition(x,y))
                    return false;
            }
           return true;
       }

       private bool IsNodeOnTarget(ConsoleNode node)
       {
           if (node.X == target.X && node.Y == target.Y)
               return true;
           return false;
       }

      

       private Position CheckPosition(int x, int y)
       {
           if (!IsPositionFree(x, y))
               return Position.Node;
           if (!gameField.IsOnField(x, y))
               return Position.Border;
           return Position.Free;
       }

       private void MoveNodeLeft(object sender, EventArgs e)
       {
            if (dir != Direction.Right)
                dir = Direction.Left;

       }
      

        private void MoveNodeRight(object sender, EventArgs e)
       {
           
            if (dir != Direction.Left)
                dir = Direction.Right;

       }


       private void MoveNodeUp(object sender, EventArgs e)
       {
            if (dir != Direction.Down)
                dir = Direction.Up;
       }

       private void MoveNodeDown(object sender, EventArgs e)
       {
            if (dir != Direction.Up)
                dir = Direction.Down;
       }
        public void EndOfTheGame()
        {
            if (isGameOver == true)
            {
                //drawer.DrawMessage(gameField, 10, "Game Over! Press any key for continue");
                drawer.DrawGameOver(10, 10, 10);
                isGameOver = false;
                tailCount = 3;
                speed = 1;
                dir = Direction.Up;
                StartGame();
            }

        }
    }


    public enum Position
    {
        Node,
        Border,
        Free
    }
    public enum Direction
    {
        Up,
        Down,
        Right,
        Left
    
    }
 

}
